package cn.fintecher.pangolin.service.dataimp.task;

import cn.fintecher.pangolin.common.enums.*;
import cn.fintecher.pangolin.common.model.DepartmentModel;
import cn.fintecher.pangolin.common.model.UserModel;
import cn.fintecher.pangolin.common.utils.ZWDateUtil;
import cn.fintecher.pangolin.entity.elastic.BaseCase;
import cn.fintecher.pangolin.entity.elastic.DataImportRecord;
import cn.fintecher.pangolin.entity.elastic.PaymentRecord;
import cn.fintecher.pangolin.entity.elastic.PaymentRecordModel;
import cn.fintecher.pangolin.entity.mysql.*;
import cn.fintecher.pangolin.service.dataimp.elastic.BaseCaseElastic;
import cn.fintecher.pangolin.service.dataimp.elastic.DataImportRecordElastic;
import cn.fintecher.pangolin.service.dataimp.elastic.PaymentRecordElastic;
import cn.fintecher.pangolin.service.dataimp.model.ConfirmCommonModel;
import cn.fintecher.pangolin.service.dataimp.repository.AssistCaseRepository;
import cn.fintecher.pangolin.service.dataimp.repository.CaseInfoRepository;
import cn.fintecher.pangolin.service.dataimp.repository.ProcessApplicationRepository;
import cn.fintecher.pangolin.service.dataimp.service.BaseService;
import cn.fintecher.pangolin.common.utils.RepositoryUtil;
import org.apache.commons.collections4.IterableUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;

/**
 * @Auther: xiaqun
 * @Description:
 * @Date: 9:36 2019/10/10
 */

@Service("confirmBillTask")
public class ConfirmBillTask {
    private static final Logger log = LoggerFactory.getLogger(ConfirmBillTask.class);

    @Autowired
    private PaymentRecordElastic paymentRecordElastic;

    @Autowired
    private DataImportRecordElastic dataImportRecordElastic;

    @Autowired
    private BaseCaseElastic baseCaseElastic;

    @Autowired
    private CaseInfoRepository caseInfoRepository;

    @Autowired
    private ProcessApplicationRepository processApplicationRepository;

    @Autowired
    private BaseService baseService;

    @Autowired
    private ConfirmBillFuture confirmBillFuture;

    @Autowired
    private AssistCaseRepository assistCaseRepository;

    /**
     * 对账单导入确认
     */
    @Async
    @Transactional
    public void confirmBill(List<PaymentRecordModel> models, UserModel userModel, DataImportRecord record, DepartmentModel departmentModel) {
        //创建任务集合
        List<CompletableFuture<List<PaymentRecord>>> list = new ArrayList<>();
        //分页处理信息
        int pageSize = 1000;
        int pageNumber = (int) Math.ceil((double) models.size() / (double) pageSize);
        for (int i = 0; i < pageNumber; i++) {
            List<PaymentRecordModel> paymentRecordModels = models.stream().skip(i * pageSize).limit(pageSize).collect(Collectors.toList());
            CompletableFuture<List<PaymentRecord>> task = confirmBillFuture.processBill(paymentRecordModels, userModel, departmentModel);
            list.add(task);
        }
        List<PaymentRecord> paymentRecords = new ArrayList<>();
        try {
            for (CompletableFuture<List<PaymentRecord>> future : list) {
                List<PaymentRecord> paymentRecordList = future.get();
                paymentRecords.addAll(paymentRecordList);
            }
            if (!paymentRecords.isEmpty()) {
                //更新案件金额
                processCase(paymentRecords);
                RepositoryUtil.saveData(paymentRecordElastic, paymentRecords);
            }
            //更新导入结果状态
            record.setStatus(ImportDataExcelStatus.CONFIRMED);
            record.process(userModel.getRealName(), ZWDateUtil.getNowDateTime());
            dataImportRecordElastic.save(record);
        } catch (InterruptedException |
                ExecutionException e) {
            log.error(e.getMessage(), e);
            record.setStatus(ImportDataExcelStatus.UN_CONFIRMED);
            record.process(userModel.getRealName(), ZWDateUtil.getNowDateTime());
            dataImportRecordElastic.save(record);
        } finally {
            baseService.sendMsg(MessageType.IMPORT_BILL_CONFIRMED, userModel);
        }
    }

    /**
     * 处理案件
     */
    private void processCase(List<PaymentRecord> paymentRecords) {
        List<String> caseNumbers = new ArrayList<>();
        for (PaymentRecord paymentRecord : paymentRecords) {
            caseNumbers.add(paymentRecord.getCaseNumber());
        }
        BoolQueryBuilder builder = new BoolQueryBuilder();
        builder.must(QueryBuilders.termsQuery("caseNumber.keyword", caseNumbers));
        Iterable<BaseCase> baseCaseIterable = baseCaseElastic.search(builder);
        Iterable<CaseInfo> caseInfoIterable = caseInfoRepository.findAll(QCaseInfo.caseInfo.caseNumber.in(caseNumbers));
        Iterable<AssistCase> assistCaseIterable = assistCaseRepository.findAll(QAssistCase.assistCase.caseNumber.in(caseNumbers)
                .and(QAssistCase.assistCase.assistStatus.in(AssistStatus.ASSIST_WAIT_ASSIGN, AssistStatus.ASSIST_COLLECTING)));
        Iterable<ProcessApplication> applicationIterable = processApplicationRepository.findAll(QProcessApplication.processApplication.caseNumber.in(caseNumbers)
                .and(QProcessApplication.processApplication.approvalStage.in(ApprovalStage.WAIT_APPROVAL, ApprovalStage.BEING_APPROVAL)));
        List<BaseCase> baseCases = IterableUtils.toList(baseCaseIterable);
        List<CaseInfo> caseInfos = IterableUtils.toList(caseInfoIterable);
        List<AssistCase> assistCases = IterableUtils.toList(assistCaseIterable);
        List<ProcessApplication> applications = IterableUtils.toList(applicationIterable);
        Map<String, ConfirmCommonModel> map = new HashMap<>();
        for (PaymentRecord paymentRecord : paymentRecords) {
            if (map.containsKey(paymentRecord.getCaseNumber())) {
                List<PaymentRecord> list = map.get(paymentRecord.getCaseNumber()).getPaymentRecords();
                list.add(paymentRecord);
                list.sort((e1, e2) -> e2.getPaymentDate().compareTo(e1.getPaymentDate()));
            } else {
                ConfirmCommonModel confirmCommonModel = new ConfirmCommonModel();
                for (BaseCase baseCase : baseCases) {
                    if (paymentRecord.getCaseNumber().equals(baseCase.getCaseNumber())) {
                        confirmCommonModel.setBaseCase(baseCase);
                        break;
                    }
                }
                for (CaseInfo caseInfo : caseInfos) {
                    if (paymentRecord.getCaseNumber().equals(caseInfo.getCaseNumber())) {
                        confirmCommonModel.setCaseInfo(caseInfo);
                        break;
                    }
                }
                List<AssistCase> assistCaseList = new ArrayList<>();
                for (AssistCase assistCase : assistCases) {
                    if (paymentRecord.getCaseNumber().equals(assistCase.getCaseNumber())) {
                        assistCaseList.add(assistCase);
                    }
                }
                confirmCommonModel.setAssistCases(assistCaseList);
                List<ProcessApplication> applicationList = new ArrayList<>();
                for (ProcessApplication application : applications) {
                    if (paymentRecord.getCaseNumber().equals(application.getCaseNumber())) {
                        applicationList.add(application);
                    }
                }
                confirmCommonModel.setApplications(applicationList);
                List<PaymentRecord> list = new ArrayList<>();
                list.add(paymentRecord);
                confirmCommonModel.setPaymentRecords(list);
                map.put(paymentRecord.getCaseNumber(), confirmCommonModel);
            }
        }
        List<BaseCase> baseCaseList = new ArrayList<>();
        List<CaseInfo> caseInfoList = new ArrayList<>();
        List<AssistCase> assistCaseList = new ArrayList<>();
        List<ProcessApplication> applicationList = new ArrayList<>();
        for (Map.Entry<String, ConfirmCommonModel> entry : map.entrySet()) {
            ConfirmCommonModel confirmCommonModel = entry.getValue();
            BaseCase baseCase = confirmCommonModel.getBaseCase();
            CaseInfo caseInfo = confirmCommonModel.getCaseInfo();
            List<AssistCase> assistCases1 = confirmCommonModel.getAssistCases();
            List<ProcessApplication> applications1 = confirmCommonModel.getApplications();
            List<PaymentRecord> list = confirmCommonModel.getPaymentRecords();
            double totle = 0d;
            for (PaymentRecord paymentRecord : list) {
                totle += paymentRecord.getPaymentAmt();
            }
            double amt = baseCase.getLeftAmt() - totle;
            baseCase.setLeftAmt(amt);
            //处理基础案件
            if (amt <= 0) {
                baseCase.setIsClear(BaseSelect.YES);
                baseCase.setPayStatus(PayStatus.SETTLT);
                baseCase.setClearDate(ZWDateUtil.getNowDate());
            } else {
                baseCase.setPayStatus(PayStatus.PARTIAL_PAY);
                baseCase.setClearDate(null);
            }
            if (Objects.isNull(baseCase.getLatestPayDate())) { //最新还款日期为空
                baseCase.setLatestPayAmt(list.get(0).getPaymentAmt());
                baseCase.setLatestPayDate(list.get(0).getPaymentDate());
            } else { //最新还款日期不为空
                if (baseCase.getLatestPayDate().getTime() < list.get(0).getPaymentDate().getTime()) { //最新还款日期小于导入日期
                    baseCase.setLatestPayAmt(list.get(0).getPaymentAmt());
                    baseCase.setLatestPayDate(list.get(0).getPaymentDate());
                }
            }
            baseCaseList.add(baseCase);
            //处理案件
            if (Objects.nonNull(caseInfo)) {
                caseInfo.setLeftAmt(amt);
                caseInfo.setCaseStatus(caseInfo.getCaseDataStatus());
                if (amt <= 0) {
                    boolean b = processApplicationRepository.existsByCaseIdAndApprovalStageAndFlowType(baseCase.getId(), ApprovalStage.APPROVED_PASS, FlowType.DERATE_APPLY);
                    if (b) {
                        caseInfo.setCaseDataStatus(CaseDataStatus.REDUCE);
                    } else {
                        caseInfo.setCaseDataStatus(CaseDataStatus.SETTLT);
                    }
                    caseInfo.setPayStatus(PayStatus.SETTLT);
                    caseInfo.setClearDate(ZWDateUtil.getNowDate());
                    //处理申请
                    for (ProcessApplication application : applications1) {
                        application.setApprovalStage(ApprovalStage.APPROVAL_CANCEL);
                        application.getProcessFlowNodes().forEach(e -> {
                            e.setApprovalStatus(ApprovalStatus.APPROVED_COMPLETED);
                            e.setApprovedResult(ApprovalResult.APPROVED_REJECT);
                            e.setApprovalTime(ZWDateUtil.getNowDateTime());
                        });
                        application.setOperatorDate(ZWDateUtil.getNowDateTime());
                        applicationList.add(application);
                    }
                } else {
                    caseInfo.setPayStatus(PayStatus.PARTIAL_PAY);
                    caseInfo.setClearDate(null);
                }
                if (Objects.isNull(caseInfo.getLatestPayDate())) { //最新还款日期为空
                    caseInfo.setLatestPayAmt(list.get(0).getPaymentAmt());
                    caseInfo.setLatestPayDate(list.get(0).getPaymentDate());
                } else { //最新还款日期不为空
                    if (caseInfo.getLatestPayDate().getTime() < list.get(0).getPaymentDate().getTime()) { //最新还款日期小于导入日期
                        caseInfo.setLatestPayAmt(list.get(0).getPaymentAmt());
                        caseInfo.setLatestPayDate(list.get(0).getPaymentDate());
                    }
                }
                caseInfoList.add(caseInfo);
            }
            //处理协催案件
            for (AssistCase assistCase : assistCases1) {
                assistCase.setLeftAmt(baseCase.getLeftAmt());
                assistCase.setLatestPayAmt(baseCase.getLatestPayAmt());
                assistCase.setLatestPayDate(baseCase.getLatestPayDate());
                if (baseCase.getLeftAmt() <= 0) {
                    assistCase.setAssistStatus(AssistStatus.ASSIST_CANCEL);
                }
            }
            assistCaseList.addAll(assistCases1);
        }
        RepositoryUtil.saveData(baseCaseElastic, baseCaseList);
        RepositoryUtil.saveData(caseInfoRepository, caseInfoList);
        RepositoryUtil.saveData(assistCaseRepository, assistCaseList);
        RepositoryUtil.saveData(processApplicationRepository, applicationList);
    }
}
